home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / arch / arm / include / asm / atomic.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  4.6 KB  |  213 lines

  1. /*
  2.  *  arch/arm/include/asm/atomic.h
  3.  *
  4.  *  Copyright (C) 1996 Russell King.
  5.  *  Copyright (C) 2002 Deep Blue Solutions Ltd.
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 2 as
  9.  * published by the Free Software Foundation.
  10.  */
  11. #ifndef __ASM_ARM_ATOMIC_H
  12. #define __ASM_ARM_ATOMIC_H
  13.  
  14. #include <linux/compiler.h>
  15. #include <asm/system.h>
  16.  
  17. typedef struct { volatile int counter; } atomic_t;
  18.  
  19. #define ATOMIC_INIT(i)    { (i) }
  20.  
  21. #ifdef __KERNEL__
  22.  
  23. #define atomic_read(v)    ((v)->counter)
  24.  
  25. #if __LINUX_ARM_ARCH__ >= 6
  26.  
  27. /*
  28.  * ARMv6 UP and SMP safe atomic ops.  We use load exclusive and
  29.  * store exclusive to ensure that these are atomic.  We may loop
  30.  * to ensure that the update happens.  Writing to 'v->counter'
  31.  * without using the following operations WILL break the atomic
  32.  * nature of these ops.
  33.  */
  34. static inline void atomic_set(atomic_t *v, int i)
  35. {
  36.     unsigned long tmp;
  37.  
  38.     __asm__ __volatile__("@ atomic_set\n"
  39. "1:    ldrex    %0, [%1]\n"
  40. "    strex    %0, %2, [%1]\n"
  41. "    teq    %0, #0\n"
  42. "    bne    1b"
  43.     : "=&r" (tmp)
  44.     : "r" (&v->counter), "r" (i)
  45.     : "cc");
  46. }
  47.  
  48. static inline int atomic_add_return(int i, atomic_t *v)
  49. {
  50.     unsigned long tmp;
  51.     int result;
  52.  
  53.     __asm__ __volatile__("@ atomic_add_return\n"
  54. "1:    ldrex    %0, [%2]\n"
  55. "    add    %0, %0, %3\n"
  56. "    strex    %1, %0, [%2]\n"
  57. "    teq    %1, #0\n"
  58. "    bne    1b"
  59.     : "=&r" (result), "=&r" (tmp)
  60.     : "r" (&v->counter), "Ir" (i)
  61.     : "cc");
  62.  
  63.     return result;
  64. }
  65.  
  66. static inline int atomic_sub_return(int i, atomic_t *v)
  67. {
  68.     unsigned long tmp;
  69.     int result;
  70.  
  71.     __asm__ __volatile__("@ atomic_sub_return\n"
  72. "1:    ldrex    %0, [%2]\n"
  73. "    sub    %0, %0, %3\n"
  74. "    strex    %1, %0, [%2]\n"
  75. "    teq    %1, #0\n"
  76. "    bne    1b"
  77.     : "=&r" (result), "=&r" (tmp)
  78.     : "r" (&v->counter), "Ir" (i)
  79.     : "cc");
  80.  
  81.     return result;
  82. }
  83.  
  84. static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
  85. {
  86.     unsigned long oldval, res;
  87.  
  88.     do {
  89.         __asm__ __volatile__("@ atomic_cmpxchg\n"
  90.         "ldrex    %1, [%2]\n"
  91.         "mov    %0, #0\n"
  92.         "teq    %1, %3\n"
  93.         "strexeq %0, %4, [%2]\n"
  94.             : "=&r" (res), "=&r" (oldval)
  95.             : "r" (&ptr->counter), "Ir" (old), "r" (new)
  96.             : "cc");
  97.     } while (res);
  98.  
  99.     return oldval;
  100. }
  101.  
  102. static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
  103. {
  104.     unsigned long tmp, tmp2;
  105.  
  106.     __asm__ __volatile__("@ atomic_clear_mask\n"
  107. "1:    ldrex    %0, [%2]\n"
  108. "    bic    %0, %0, %3\n"
  109. "    strex    %1, %0, [%2]\n"
  110. "    teq    %1, #0\n"
  111. "    bne    1b"
  112.     : "=&r" (tmp), "=&r" (tmp2)
  113.     : "r" (addr), "Ir" (mask)
  114.     : "cc");
  115. }
  116.  
  117. #else /* ARM_ARCH_6 */
  118.  
  119. #include <asm/system.h>
  120.  
  121. #ifdef CONFIG_SMP
  122. #error SMP not supported on pre-ARMv6 CPUs
  123. #endif
  124.  
  125. #define atomic_set(v,i)    (((v)->counter) = (i))
  126.  
  127. static inline int atomic_add_return(int i, atomic_t *v)
  128. {
  129.     unsigned long flags;
  130.     int val;
  131.  
  132.     raw_local_irq_save(flags);
  133.     val = v->counter;
  134.     v->counter = val += i;
  135.     raw_local_irq_restore(flags);
  136.  
  137.     return val;
  138. }
  139.  
  140. static inline int atomic_sub_return(int i, atomic_t *v)
  141. {
  142.     unsigned long flags;
  143.     int val;
  144.  
  145.     raw_local_irq_save(flags);
  146.     val = v->counter;
  147.     v->counter = val -= i;
  148.     raw_local_irq_restore(flags);
  149.  
  150.     return val;
  151. }
  152.  
  153. static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
  154. {
  155.     int ret;
  156.     unsigned long flags;
  157.  
  158.     raw_local_irq_save(flags);
  159.     ret = v->counter;
  160.     if (likely(ret == old))
  161.         v->counter = new;
  162.     raw_local_irq_restore(flags);
  163.  
  164.     return ret;
  165. }
  166.  
  167. static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
  168. {
  169.     unsigned long flags;
  170.  
  171.     raw_local_irq_save(flags);
  172.     *addr &= ~mask;
  173.     raw_local_irq_restore(flags);
  174. }
  175.  
  176. #endif /* __LINUX_ARM_ARCH__ */
  177.  
  178. #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
  179.  
  180. static inline int atomic_add_unless(atomic_t *v, int a, int u)
  181. {
  182.     int c, old;
  183.  
  184.     c = atomic_read(v);
  185.     while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
  186.         c = old;
  187.     return c != u;
  188. }
  189. #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
  190.  
  191. #define atomic_add(i, v)    (void) atomic_add_return(i, v)
  192. #define atomic_inc(v)        (void) atomic_add_return(1, v)
  193. #define atomic_sub(i, v)    (void) atomic_sub_return(i, v)
  194. #define atomic_dec(v)        (void) atomic_sub_return(1, v)
  195.  
  196. #define atomic_inc_and_test(v)    (atomic_add_return(1, v) == 0)
  197. #define atomic_dec_and_test(v)    (atomic_sub_return(1, v) == 0)
  198. #define atomic_inc_return(v)    (atomic_add_return(1, v))
  199. #define atomic_dec_return(v)    (atomic_sub_return(1, v))
  200. #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
  201.  
  202. #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
  203.  
  204. /* Atomic operations are already serializing on ARM */
  205. #define smp_mb__before_atomic_dec()    barrier()
  206. #define smp_mb__after_atomic_dec()    barrier()
  207. #define smp_mb__before_atomic_inc()    barrier()
  208. #define smp_mb__after_atomic_inc()    barrier()
  209.  
  210. #include <asm-generic/atomic.h>
  211. #endif
  212. #endif
  213.